
//
// Copyright 2009 Arne Halvorsen (arne.halvorsen@gmail.com)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

// Project page: http://code.google.com/p/webfg/

//
// 091201 - aha42 - Created.
// 091211 - aha42 - getKey(ServletRequest) and methods that used to accept
//                  HttpServletRequest now accepts ServletRequest.
// 091220 - aha42 - Methods to get boolean parameters.
//

package org.aha.servlet;

import java.util.Enumeration;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.servlet.ServletRequest;

/**
 * <p>
 *   Utility patterns of use when working with parameters of a HTTP request.
 * </p>
 * @author Arne Halvorsen (aha42).
 */
public final class ParameterUtil 
{
  private ParameterUtil(){} // Utility pattern dictates private constructor.
  
  /**
   * <p>
   *   Gets parameter that has a default value.
   * </p>
   * @param name Parameter name.
   * @param def  Default value.
   * @param req  Request to get parameter from.
   * @return Value.
   */
  public static String getParameter(String name, String def, ServletRequest req)
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (def==null)
    {
      throw new NullPointerException("def");
    }
    if (req==null)
    {
      throw new NullPointerException("req");
    }
    
    String val=req.getParameter(name);
    return val==null ? def : val;
  }
  /**
   * <p>
   *   Gets mandatory request parameter.
   * </p>
   * @param name Parameter name.
   * @param req  Request to get parameter from.
   * @return Value.
   * @throws MissingRequestParameterException If parameter not found.
   */
  public static String getMandatoryParameter(String name, ServletRequest req) 
    throws MissingRequestParameterException
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (req==null)
    {
      throw new NullPointerException("req");
    }
    
    String retVal=req.getParameter(name);
    if (retVal==null)
    {
      throw new MissingRequestParameterException(name);
    }
    return retVal;
  }
  
  /**
   * <p>
   *   Gets request parameter as {@code int} value. 
   * </p>
   * @param name Parameter name.
   * @param req  Request.
   * @return Value or {@code null} if not found.
   * @throws RequestParseException If could not parse parameter as an 
   *         {@code int}.
   */
  public static Integer getIntParameter(String name, ServletRequest req) 
    throws RequestParseException
  { 
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (req==null)
    {
      throw new NullPointerException("req");
    }
    
    String val=req.getParameter(name);
    try
    {
      return val==null ? null : new Integer(val);
    }
    catch (NumberFormatException nfx)
    {
      throw new RequestParameterTypeException("parameter "+name+" not int");  
    }
  }
  
  /**
   * <p>
   *   Gets request parameter as {@code int} value. 
   * </p>
   * @param name Parameter's name.
   * @param def  Default value.
   * @param req  Request.
   * @return Value.
   * @throws RequestParseException If could not parse parameter as an 
   *         {@code int}.
   */
  public static int getIntParameter(String name, int def, ServletRequest req)
    throws RequestParseException
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (req==null)
    {
      throw new NullPointerException("req");
    }
    
    String val=req.getParameter(name);
    try
    {
      return val==null ? def : Integer.parseInt(val);
    }
    catch (NumberFormatException nfx)
    {
      throw new RequestParameterTypeException("parameter "+name+" not int");  
    }
  }
  
  /**
   * <p>
   *   Gets default request parameter as {@code int} value. 
   * </p>
   * @param name Parameter's name.
   * @param req  Request.
   * @return Value.
   * @throws RequestParseException If could not parse parameter as an 
   *         {@code int}.
   * @throws MissingRequestParameterException If parameter not found.         
   */
  public static int getMandatoryIntParameter(String name, 
    ServletRequest req) throws RequestParseException
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (req==null)
    {
      throw new NullPointerException("req");
    }
    
    String val=getMandatoryParameter(name, req);
    try
    {
      return Integer.parseInt(val);
    }
    catch (NumberFormatException nfx)
    {
      throw new RequestParameterTypeException("parameter "+name+" not int");  
    }
  }
  
  /**
   * <p>
   *   Gets request parameter as {@code boolean} value.
   * </p>
   * <p>
   *   Values {@code 1, true, yes} and {@code on} ignoring case is parsed as
   *   {@code true} and values {@code 0, false, no} and {@code off} ignoring
   *   case is parsed as {@code false}. 
   * </p> 
   * @param name Parameter name.
   * @param def  Default name.
   * @param req  Request.
   * @return Value.
   * @throws RequestParseException If could not parse parameter as an 
   *         {@code boolean}.
   */
  public static boolean getBooleanParameter(String name, boolean def, 
    ServletRequest req) throws RequestParseException
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (req==null)
    {
      throw new NullPointerException("req");
    }
    
    String val=req.getParameter(name);
    if (val==null) return def;
    
    return parseBoolean(name, val);
  }
  
  /**
   * <p>
   *   Gets request parameter as {@code boolean} value. 
   * </p>
   * <p>
   *   Values {@code 1, true, yes} and {@code on} ignoring case is parsed as
   *   {@code true} and values {@code 0, false, no} and {@code off} ignoring
   *   case is parsed as {@code false}. 
   * </p> 
   * @param name Parameter name.
   * @param req  Request.
   * @return Value or {@code null} if not found.
   * @throws RequestParseException If could not parse parameter as an 
   *         {@code boolean}.
   */
  public static Boolean getBooleanParameter(String name, ServletRequest req) 
    throws RequestParseException
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (req==null)
    {
      throw new NullPointerException("req");
    }
    
    String val=req.getParameter(name);
    return val==null ? null : parseBoolean(name, val);
  }
  
  /**
   * <p>
   *   Gets mandatory request parameter as {@code boolean} value.
   * </p>
   * <p>
   *   Values {@code 1, true, yes} and {@code on} ignoring case is parsed as
   *   {@code true} and values {@code 0, false, no} and {@code off} ignoring
   *   case is parsed as {@code false}. 
   * </p>
   * @param name Parameter name.
   * @param def  Default name.
   * @param req  Request.
   * @return Value.
   * @throws RequestParseException If could not parse parameter as an 
   *         {@code boolean}.
   * @throws MissingRequestParameterException If parameter not found.         
   */
  public static boolean getMandatoryBooleanParameter(String name, 
    ServletRequest req) throws RequestParseException
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (req==null)
    {
      throw new NullPointerException("req");
    }
    
    return parseBoolean(name, getMandatoryParameter(name, req));
  }
  
  // Invoked from utility methods that get parameter values as boolean.
  private static boolean parseBoolean(String name, String val) 
    throws RequestParseException
  {
    if (val.equalsIgnoreCase("true"))  return true;
    if (val.equalsIgnoreCase("yes"))   return true;
    if (val.equalsIgnoreCase("on"))    return true;
    if (val.equals("1"))               return true;
    if (val.equalsIgnoreCase("false")) return false;
    if (val.equalsIgnoreCase("no"))    return false;
    if (val.equalsIgnoreCase("off"))   return false;
    if (val.equals("0"))               return false;
    
    throw new RequestParameterTypeException("parameter "+name+" not boolean");
  }
  
  /**
   * <p>
   *   Gets key for request by sorting parameters by name and then concatenate
   *   names and values.
   * </p>
   * <p>
   *   One use is to lookup cached query result server side.
   * </p>
   * @param req Request to generate key for.
   * @return Key.
   */
  @SuppressWarnings("unchecked")
  public static String getRequestKey(ServletRequest req)
  {
    if (req==null)
    {
      throw new NullPointerException("req");
    }
    
    StringBuilder sb=null;
    
    Enumeration names=req.getParameterNames();
    SortedSet<String> sorted=new TreeSet<String>();
    while (names.hasMoreElements()) sorted.add(names.nextElement().toString());
    Iterator<String> i=sorted.iterator();
    while (i.hasNext())
    {
      if (sb==null) sb=new StringBuilder();
      String name=i.next();
      String value=req.getParameter(name);
      name=(name==null) ? "" : name.trim();
      sb.append(name).append(value);
    }
    return sb==null ? "" : sb.toString();
  }
  
}
